﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using Seagull.Configuration;
using Seagull.Generic;
using Seagull.Model.Sms;

namespace Seagull.ZHD1X
{
    public class FailedSmsMessages
    {
        private static readonly XmlSerializer _xmlSerializer = new XmlSerializer(typeof (FailedSmsMessages));

        private static readonly object _syncRoot = new object();

        internal FailedSmsMessages()
        {
            Messages = new List<SmsMessage>();
        }

        public List<SmsMessage> Messages { get; set; }

        private static FailedSmsMessages LoadOrCreate()
        {
            try
            {
                using(var fileStream = FileHelper.Open(() =>
                    File.OpenRead(Config.Instance.PathConfig.FailedSmsAlertFile)))
                {
                    return (FailedSmsMessages) _xmlSerializer.Deserialize(fileStream);
                }
            }
            catch (IOException)
            {
                return CreateNew();
            }
            catch (InvalidOperationException)
            {
                // 反序列化失败，删除并新建文件
                if (File.Exists(Config.Instance.PathConfig.FailedSmsAlertFile))
                {
                    File.Delete(Config.Instance.PathConfig.FailedSmsAlertFile);
                }
                return CreateNew();
            }
        }

        private static FailedSmsMessages CreateNew()
        {
            var directory = Path.GetDirectoryName(Config.Instance.PathConfig.FailedSmsAlertFile);
            if (!string.IsNullOrEmpty(directory))
            {
                Directory.CreateDirectory(directory);
            }
            var failedSmsAlerts = new FailedSmsMessages();
            failedSmsAlerts.Save();
            return failedSmsAlerts;
        }

        public static void Change(Action<FailedSmsMessages> change)
        {
            lock (_syncRoot)
            {
                var failedSmsAlerts = LoadOrCreate();
                change(failedSmsAlerts);
                failedSmsAlerts.Save();
            }
        }

        public static T Change<T>(Func<FailedSmsMessages, T> change)
        {
            lock (_syncRoot)
            {
                var failedSmsAlerts = LoadOrCreate();
                var result = change(failedSmsAlerts);
                failedSmsAlerts.Save();
                return result;
            }
        }

        private void Save()
        {
            using(var fileStream = FileHelper.Open(() => 
                File.Open(Config.Instance.PathConfig.FailedSmsAlertFile, 
                    FileMode.Create, FileAccess.Write, FileShare.None)))
            {
                _xmlSerializer.Serialize(fileStream, this);
            }
        }
    }
}